[TOC]

Anonymous Function

Anonymous functions allow you to create a function without the need of creating a .m file. They are often useful in situations like the one described below.

Suppose that you want to run a root-finding algorithm to search for a root of, say, . Then, you can defined an anonymous function for :

f = @(x) 3*x.^3+x.^2-1

Here, f is a function handle pointing to the anonymous function @(x) 3*x.^3+x.^2-1. The function handle can then be passed to the following root-finding function as an input argument:

% f is a function handle of an anonymous function.
% x0 defines an initial point

function r = find_root(x0, f)

Using a function handle as an input argument allows find_root to be used for other mathematical functions. For example, if we want to search for the root of another function, say, , we can create f = @(x)x.^2-1 and pass it to find_root(x0, f). There is no need to create an extra .m file.

Syntax

An anonymous function is defined using the following syntax:

f = @() expression
f = @(x1,x2,...,xn) expression

Here, x1, x2, ..., xn are input arguments of f, and expression is the expression to be evaluated in a function call. Use @()if the function expects no input argument.

⚠️⚠️⚠️ It should be noted that only one expression written in a single line can be used. Moreover, statements like loops, if-else statement, switch statement, and variable assignment cannot be used in an anonymous function. Hence, it is not suitable for evaluating "complicated" functions.

Function Evaluation

The following example defines and evaluates , and . In Line 2, no output variable is provided. In this case, the output f(1) is assigned to the system variable ans. In Line 3, the output is assigned to the variable f2.

f = @(x) 3*x.^3+x.^2-1
f(1)
f2 = f(2)

An anonymous function can have more than 1 output. The number of outputs depends on the number of variables provided on the left-hand side of the assignment. Consider this example, where the mysize(x) gives the size of an array x:

mysize = @(x) size(x)

Recall that size is a built-in function that

The function handle mysize defined above behaves in the exact same way the built-in function size:

Input
mysize = @(x)size(x);
% One output variable; giving size vector
vec = mysize(rand(3,4))
% Two output varialbes; giving dimension lengths.
[len1, len2] = mysize(rand(3,4))
Output
vec = 
 3.0000   4.0000

len1 = 
 3.0000

len2 = 
 4.0000

The following function requires no input argument and it is called using pi_2(). We need to add parenthesies after pi_2, since pi_2 returns the function handle, not the value.

Input
% Defining the function.
pi_2 = @() pi / 2;
% Printing the defintion of the function.
pi_2
% Running the function
pi_2()
Output
pi_2 = (anonymous function)
 @()pi/2

ans = 
 1.5707963

Nested Anonymous Functions

An anonymous function can be used in another anonymous function. For example, we can define , where the derivative is defined as :

Input
df = @(x) x + 1
h = @(x,y) df(x) + y
Output
df = (anonymous function)
 @(x)x+1

h = (anonymous function)
 @(x, y)df(x)+y

Then, we run to obtain :

Input
h(1,2)
Output
ans = 
 4.0000

Variable Scope

When an anonymous function is created, variables defined before it in the current workspace will be stored. You can think of this as taking a “snapshot” of the workspace in which the anonymous function is defined. Variables in this snapshot will be loaded into the anonymous function's "local" workspace when the function is evaluated. These variables have local scope inside the anonymous function's workspace, and they persist even if you clear the variables from other workspaces.

This idea is illustrated in the example below.

clear
a = 1;
b = 1;
f = @(x,y)x + y + a + b
g = @(x,y)f(x,y) + a * b

The script above has its workspace. If the script is run in the console, it is the global workspace. If the script is contained in a user-defined function, the workspace belongs to the user-defined function. Moreover, each of the anonymous functions (f and g) has its own "local" workspace. The relationship between these workspaces are shown in the figure below.

Anonymous function workspaces

We demonstrate this relationship by code below. We enter the script in the console:

Input
clear
a = 1;
b = 2;
f = @(x,y)x + y + a + b
g = @(x,y)f(x, y) + a * b
Output
All variables cleared
f = (anonymous function)
 @(x, y)x+y+a+b

g = (anonymous function)
 @(x, y)f(x,y)+a*b

Then, we run f(1,2) to get 1 + 2 + 1 + 2 equal to 6. This is because a = 1 and b = 2 are defined in the workspace of f.

Input
f(1,2)
Output
ans = 
 6.0000

Next, we run g(0.5, 0.3) to get 5.8. This is because

Clearing a b from the global workspace does not affect the workspaces of f and g. Similar, clearing f from the global workspace does not affect the workspace of g. All of the variables captured by the anonymous functions always persist.

Input
clear('a','b')
f(1,2)
g(0.5,0.3)
clear('f')
g(0.5,0.3)
Output
Variables "a", "b", have been cleared
ans = 
 6.0000

ans = 
 5.8000

Variable "f", has been cleared
ans = 
 5.8000

Anonymous Function As Input Argument

Anonymous functions can be passed to another function as input arguments. The following bisection uses a bisection algorithm to search for a root of the equation . It requires 4 input arguments, namely, the initial left bound a1, the initial right bound b1, the tolerance epsilon, and the function f.

% Bisection algorithm
function mk = bisection(a1,b1,epsilon,f)

if a1 > b1
    disp('a1 should be smaller than b1');
    disp('Terminated');
    return;
end

if f(a1) * f(b1) > 0
    disp('f(a1) and f(b1) have the same signs');
    disp('Bisection cannot start. Choose another a1 and b1');
    disp('Terminated')
    return;
end

% 1st iteration.
k = 1;
ak = a1;
bk = b1;
mk = (a1 + b1) / 2;

% Continue until stopping condition is met.
while abs(f(mk)) > epsilon
    if f(mk) * f(ak) < 0
        bk = mk;
    else
        ak = mk;
    end
    disp(['Iter ' int2str(k)])
    mk = (ak + bk) / 2
    k = k + 1;
end

Suppose we want to search for a root of within the initial bound with a tolerance of 0.01. Then, we call the following:

r = bisection(pi/2, 3*pi / 2, 0.01, @(x) sin(x) + 1)
Iter 1
mk = 
 3.9269908

Iter 2
mk = 
 4.3196899

Iter 3
mk = 
 4.5160394

Iter 4
mk = 
 4.6142142

r = 
 4.6142142

The above bisection algorithm terminates after 4 iterations with an estimate (4.6142142) of the root of .

Array of Anonymous Functions

Although a function handle can be stored as a variable in a workspace, an array of function handles is not allowed. MATLAB can store function handles in a cell array. However, cell array is not supported yet in the current version of SIMO.